package yxy.game.pm2.bean;

import org.redisson.api.RMap;
import yxy.apple.util.RandomStringUtility;
import yxy.apple.util.RandomUtility;
import yxy.apple.util.RandomUtility.Weight;
import yxy.apple.util.StringUtillity;
import yxy.apple.util.redisson.RedisException;
import yxy.cherry.data.DataCenter;
import yxy.cherry.data.bean.*;
import yxy.cherry.data.string.GameString;
import yxy.cherry.game.base.redis.RedisManager;
import yxy.game.pm2.bean.db.newDao.SoulDAO;
import yxy.game.pm2.bean.db.po.SoulPo;
import yxy.game.pm2.bean.module.BaseGameRedisLockBean;
import yxy.game.pm2.bean.mq.CCReason;

import java.util.*;

import static yxy.apple.util.StringTrans.arrayList2String;
import static yxy.apple.util.StringTrans.string2ArrayList;

/**
 * 魂玉
 */
public class Soul extends BaseGameRedisLockBean {

    public static int maxNum = 100;

    // bean===========================================================================

    private String code;
    private int dataId;
    private int quality;
    private int refine;
    private ArrayList<Integer> propertyIds = new ArrayList<>();
    private ArrayList<Integer> skillIds = new ArrayList<>();
    private ArrayList<Integer> propertyLocks = new ArrayList<>();//锁
    private ArrayList<Integer> skillLocks = new ArrayList<>();//锁

    // 重铸
    private ArrayList<Integer> rePropertyIds;
    private ArrayList<Integer> reSkillIds;

    // 装配的武将code
    private String hero;

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public int getDataId() {
        return dataId;
    }

    public void setDataId(int dataId) {
        this.dataId = dataId;
    }

    public int getQuality() {
        return quality;
    }

    public void setQuality(int quality) {
        this.quality = quality;
    }

    public int getRefine() {
        return refine;
    }

    public void setRefine(int refine) {
        this.refine = refine;
    }

    public ArrayList<Integer> getPropertyIds() {
        return propertyIds;
    }

    public void setPropertyIds(ArrayList<Integer> propertyIds) {
        this.propertyIds = propertyIds;
    }

    public ArrayList<Integer> getSkillIds() {
        return skillIds;
    }

    public void setSkillIds(ArrayList<Integer> skillIds) {
        this.skillIds = skillIds;
    }

    public ArrayList<Integer> getRePropertyIds() {
        return rePropertyIds;
    }

    public void setRePropertyIds(ArrayList<Integer> rePropertyIds) {
        this.rePropertyIds = rePropertyIds;
    }

    public ArrayList<Integer> getReSkillIds() {
        return reSkillIds;
    }

    public void setReSkillIds(ArrayList<Integer> reSkillIds) {
        this.reSkillIds = reSkillIds;
    }

    public String getHero() {
        return hero;
    }

    public void setHero(String hero) {
        this.hero = hero;
    }

    public ArrayList<Integer> getPropertyLocks() {
        return propertyLocks;
    }

    public void setPropertyLocks(ArrayList<Integer> propertyLocks) {
        this.propertyLocks = propertyLocks;
    }

    public ArrayList<Integer> getSkillLocks() {
        return skillLocks;
    }

    public void setSkillLocks(ArrayList<Integer> skillLocks) {
        this.skillLocks = skillLocks;
    }

// redis==========================================================================

    static public String key(String playerCode) {
        return String.format("PLAYER:%s:SOUL", playerCode);
    }

    static private RMap<String, Soul> touch(String playerCode) throws RedisException {
        RMap<String, Soul> soulRMap = RedisManager.client(redis()).getMap(key(playerCode));
        if (!soulRMap.isExists()) { //从db读
            List<SoulPo> soulPoList = SoulDAO.getList(playerCode);
            if (soulPoList != null && soulPoList.size() > 0) {
                for (int i = 0; i < soulPoList.size(); i++) {
                    Soul soul = new Soul();
                    soul.setCode(soulPoList.get(i).getCode());
                    soul.setDataId(soulPoList.get(i).getDataId());
                    soul.setHero(soulPoList.get(i).getHero());
                    soul.setPropertyIds(string2ArrayList(soulPoList.get(i).getPropertyIds()));
                    soul.setQuality(soulPoList.get(i).getQuality());
                    soul.setRefine(soulPoList.get(i).getRefine());
                    soul.setSkillIds(string2ArrayList(soulPoList.get(i).getSkillIds()));
                    soul.setRePropertyIds(string2ArrayList(soulPoList.get(i).getRePropertyIds()));
                    soul.setReSkillIds(string2ArrayList(soulPoList.get(i).getReSkillIds()));
                    soul.setSkillLocks(string2ArrayList(soulPoList.get(i).getSkillLocks()));
                    soul.setPropertyLocks(string2ArrayList(soulPoList.get(i).getPropertyLocks()));
                    soulRMap.put(soulPoList.get(i).getCode(), soul);
                }
            }
        }
        return soulRMap;
    }

    static public Map<String, Soul> all(String playerCode) {
        try {
            Map<String, Soul> souls = touch(playerCode).readAllMap();
            return souls;
        } catch (RedisException e) {
        }
        return new HashMap<>();
    }

    public static void remove(String playerCode, Soul soul) {
        try {
            touch(playerCode).remove(soul.getCode());
        } catch (RedisException e) {
        }
    }

    public static void remove(String playerCode, Collection<Soul> souls) {
        try {
            RMap<String, Soul> touch = touch(playerCode);
            for (Soul soul : souls) {
                touch.remove(soul.getCode());
            }
        } catch (RedisException e) {
        }
    }

    static public Soul get(String playerCode, String code) {
        try {
            Soul soul = touch(playerCode).get(code);
            return soul;
        } catch (Exception e) {
            return null;
        }
    }

    public static long getNumber(String playerCode, int dataId) {
        try {
            RMap<String, Soul> souls = touch(playerCode);
            int number = 0;
            for (Soul soul : souls.values()) {
                if (soul.getDataId() == dataId) {
                    number++;
                }
            }
            return number;
        } catch (RedisException e) {
            e.printStackTrace();
        }
        return 0;
    }

    static public boolean set(String playerCode, Soul soul) {
        try {
            RMap<String, Soul> souls = touch(playerCode);
            souls.put(soul.code, soul);
            return true;
        } catch (RedisException e) {
            e.printStackTrace();
            return false;
        }
    }

    public static void create(String playerCode, int dataId, long number) throws RedisException {
        souldata data = DataCenter.getData(dataId, souldata.class);
        if (data == null) {
            throw new NullPointerException("数据不存在");
        }
        for (int i = 0; i < number; i++) {
            create(data, playerCode);
        }
    }

    /**
     * @param data
     * @param playerCode
     * @return
     * @throws RedisException
     */
    static public Soul create(souldata data, String playerCode) throws RedisException {
        try {
            if (lockSoul(playerCode)) {
                RMap<String, Soul> souls = touch(playerCode);
                String code = randomSoulCode();
                while (souls.containsKey(code)) {
                    code = randomSoulCode();
                }

                Soul soul = new Soul();
                soul.setCode(code);
                soul.setDataId(data.getId());
                soul.setQuality(data.getQuality());

                {
                    soulrandom _proprandom = DataCenter.getData(data.getAttributeid(), soulrandom.class);
                    soulrandom _skillrandom = DataCenter.getData(data.getSkillid(), soulrandom.class);

                    soul.randomSoul(_proprandom, RandomUtility.nextInt(data.getAttributemin(), data.getAttributemax() + 1));
                    soul.randomSoul(_skillrandom, RandomUtility.nextInt(data.getSkillmin(), data.getSkillmax() + 1));
                }

                souls.put(code, soul);
                return soul;

            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            unlockSoul(playerCode);
        }
        return null;
    }

    /**
     * 生成一个新魂玉
     */
    static public Soul create(int dataId, String playerCode) throws RedisException {
        souldata data = DataCenter.getData(dataId, souldata.class);
        if (data == null) {
            throw new NullPointerException("数据不存在");
        }
        return create(data, playerCode);
    }

    static private String randomSoulCode() {
        return String.format("ss%s", RandomStringUtility.randomLowerNumeric(4));
    }

    // func==========================================================================

    /**
     * 精炼
     */
    public boolean refine(String playerCode, soulrefine _soulrefine) {
        try {
            if (lockSoul(playerCode)) {
                souldata data = DataCenter.getData(getDataId(), souldata.class);
                if (data.getFineheave() <= 0) {
                    return false;
                }
                souldata nextdata = DataCenter.getData(data.getUpgradeid(), souldata.class);
                soulrandom _addrandom = DataCenter.getData(nextdata.getHeaveattributeid(), soulrandom.class);
                randomSoul(_addrandom, _soulrefine.getAttributenum());

                ArrayList<Integer> upSkillIds = new ArrayList<>();
                for (Integer skillId : getSkillIds()) {
                    skillgroup _skill = DataCenter.getData(skillId, skillgroup.class);
                    int upskillId = _skill.getUpid();
                    skill _upskill = DataCenter.getData(upskillId, skill.class);
                    if (_upskill != null) {
                        upSkillIds.add(_upskill.getId());
                    } else {
                        upSkillIds.add(skillId);
                    }
                }

                setSkillIds(upSkillIds);
                setDataId(nextdata.getId());
                setQuality(nextdata.getQuality());
                setRefine(_soulrefine.getId());

                set(playerCode, this);
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            unlockSoul(playerCode);
        }
        return false;
    }

    /**
     * 重铸
     */
    public void recoin(String playerCode, List<Integer> propertyLocksList, List<Integer> skillLocksList) {
        try {
            if (lockSoul(playerCode)) {

                reSkillIds = null;
                rePropertyIds = null;

                souldata data = DataCenter.getData(getDataId(), souldata.class);
                soulrandom _proprandom = DataCenter.getData(data.getAttributeid(), soulrandom.class);
                soulrandom _skillrandom = DataCenter.getData(data.getSkillid(), soulrandom.class);
                soulrandom _addrandom = DataCenter.getData(data.getHeaveattributeid(), soulrandom.class);

                int propNum = RandomUtility.nextInt(data.getAttributemin(), data.getAttributemax() + 1);
                int skillNum = RandomUtility.nextInt(data.getSkillmin(), data.getSkillmax() + 1);

                if (skillLocksList != null && skillLocksList.size() > 0 && skillNum < getSkillIds().size()) {
                    skillNum = getSkillIds().size();
                }

                if (propertyLocksList != null && propertyLocksList.size() > 0 && propNum < getPropertyIds().size()) {
                    propNum = getPropertyIds().size();
                }


                recoinSoul(_proprandom, propNum, propertyLocksList, null);
                recoinSoul(_skillrandom, skillNum, null, skillLocksList);//技能加入锁功能
                if (getPropertyIds().size() <= 2) {
                    recoinSoul(_addrandom, 1, null, null);
                }

                ArrayList<Integer> skillList = new ArrayList<>();
                for (int i = 0; skillLocksList != null && i < skillLocksList.size(); i++) {
                    skillList.add(skillLocksList.get(i));
                }

                ArrayList<Integer> propertyList = new ArrayList<>();
                for (int i = 0; propertyLocksList != null && i < propertyLocksList.size(); i++) {
                    propertyList.add(propertyLocksList.get(i));
                }

                setSkillLocks(skillList);
                setPropertyLocks(propertyList);

                set(playerCode, this);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            unlockSoul(playerCode);
        }
    }

    private void recoinSoul(soulrandom data, int num, List<Integer> propertyLocksList, List<Integer> skillLocksList) {
        if (data == null) {
            return;
        }

        List<Reward> result = RandomUtility.randomWeight(soulrandomList(data), null, num);//随机的权重

        int maxNum = 0;//保险 循环次数超20不再循环
        ArrayList<Integer> skillTypeList = new ArrayList<>();
        ArrayList<String> propertyTypeList = new ArrayList<>();
        Reward one = RandomUtility.randomWeight(soulrandomList(data));//获取其中一个
        for (int i = 0; skillLocksList != null && i < skillLocksList.size(); i++) {
            int skillId = getSkillIds().get(skillLocksList.get(i) - 1);
            skillgroup skillgroup = DataCenter.getData(skillId, skillgroup.class);
            if (skillgroup != null) skillTypeList.add(skillgroup.getSkilltype());
        }

        for (int i = 0; propertyLocksList != null && i < propertyLocksList.size(); i++) {
            int properId = getPropertyIds().get(propertyLocksList.get(i) - 1);
            soulatt soulatt = DataCenter.getData(properId, soulatt.class);
            if (soulatt != null) {
                String key =  soulatt.getType()+"_"+soulatt.getAttributetype();
                propertyTypeList.add(key);
            }
        }

        if (propertyLocksList != null) {
            for (int i = 0; i < num; i++) {
                if (rePropertyIds == null) {
                    rePropertyIds = new ArrayList<>();
                }
                //锁上的技能词条不变
                if (propertyLocksList.contains(i + 1)) {
                    rePropertyIds.add(getPropertyIds().get(i));
                    continue;
                }

                while (true) {
                    maxNum++;
                    soulatt soulatt = DataCenter.getData(one.id, soulatt.class);
                    if (soulatt == null) break;
                    if (maxNum >= 20) break;
                    String key =  soulatt.getType()+"_"+soulatt.getAttributetype();
                    if(!propertyTypeList.contains(key)){
                        propertyTypeList.add(key);
                        break;
                    }
                    one = RandomUtility.randomWeight(soulrandomList(data));
                }

                //没锁上的随机
                rePropertyIds.add(one.id);
            }
            return;
        }

        if (skillLocksList != null) {
            for (int i = 0; i < num; i++) {
                if (reSkillIds == null) {
                    reSkillIds = new ArrayList<>();
                }
                //锁上的技能词条不变
                if (skillLocksList.contains(i + 1)) {
                    reSkillIds.add(getSkillIds().get(i));
                    continue;
                }

                while (true) {
                    maxNum++;
                    skillgroup skill = DataCenter.getData(one.id, skillgroup.class);
                    if (skill == null) break;
                    if (maxNum >= 20) break;
                    if (!skillTypeList.contains(DataCenter.getData(one.id, skillgroup.class).getSkilltype())) {
                        skillTypeList.add(DataCenter.getData(one.id, skillgroup.class).getSkilltype());
                        break;
                    }
                    one = RandomUtility.randomWeight(soulrandomList(data));
                }

                //没锁上的随机
                reSkillIds.add(one.id);
            }
            return;
        }

        for (Reward reward : result) {
            switch (reward.type) {
                case 1:// skill
                {
                    if (reSkillIds == null) {
                        reSkillIds = new ArrayList<>();
                    }
                    while (true) {
                        maxNum++;
                        skillgroup skill = DataCenter.getData(one.id, skillgroup.class);
                        if (skill == null) break;
                        if (maxNum >= 20) break;
                        if (!skillTypeList.contains(DataCenter.getData(one.id, skillgroup.class).getSkilltype())) {
                            skillTypeList.add(DataCenter.getData(one.id, skillgroup.class).getSkilltype());
                            break;
                        }
                        one = RandomUtility.randomWeight(soulrandomList(data));
                    }
                    reSkillIds.add(one.id);
                }
                break;
                case 2:// prop
                {
                    if (rePropertyIds == null) {
                        rePropertyIds = new ArrayList<>();
                    }

                    while (true) {
                        maxNum++;
                        soulatt soulatt = DataCenter.getData(one.id, soulatt.class);
                        if (soulatt == null) break;
                        if (maxNum >= 20) break;
                        String key =  soulatt.getType()+"_"+soulatt.getAttributetype();
                        if(!propertyTypeList.contains(key)){
                            propertyTypeList.add(key);
                            break;
                        }
                        one = RandomUtility.randomWeight(soulrandomList(data));
                    }
                    rePropertyIds.add(one.id);
                }
                break;
            }
        }
    }

    public void randomSoul(soulrandom data, int num) {
        if (data == null) {
            return;
        }
        List<Reward> result = RandomUtility.randomWeight(soulrandomList(data), null, num);
        int maxNum = 0;//保险 循环次数超20不再循环
        ArrayList<Integer> skillTypeList = new ArrayList<>();
        ArrayList<String> propertyTypeList = new ArrayList<>();
        Reward one = RandomUtility.randomWeight(soulrandomList(data));//获取其中一个

        for (Reward reward : result) {
            switch (reward.type) {
                case 1:// skill

                    while (true) {
                        maxNum++;
                        skillgroup skill = DataCenter.getData(one.id, skillgroup.class);
                        if (skill == null) break;
                        if (maxNum >= 20) break;
                        if (!skillTypeList.contains(DataCenter.getData(one.id, skillgroup.class).getSkilltype())) {
                            skillTypeList.add(DataCenter.getData(one.id, skillgroup.class).getSkilltype());
                            break;
                        }
                        one = RandomUtility.randomWeight(soulrandomList(data));
                    }

                    skillIds.add(one.id);
                    break;
                case 2:// prop

                    while (true) {
                        maxNum++;
                        soulatt soulatt = DataCenter.getData(one.id, soulatt.class);
                        if (soulatt == null) break;
                        if (maxNum >= 20) break;
                        String key =  soulatt.getType()+"_"+soulatt.getAttributetype();
                        if(!propertyTypeList.contains(key)){
                            propertyTypeList.add(key);
                            break;
                        }
                        one = RandomUtility.randomWeight(soulrandomList(data));
                    }

                    propertyIds.add(one.id);
                    break;
            }
        }
    }

    private List<Reward> soulrandomList(soulrandom data) {
        ArrayList<Reward> list = new ArrayList<>();
        for (int i = 0; i < data.getType().length; i++) {
            list.add(new Reward(data.getType()[i], data.getRanid()[i], data.getPercent()[i]));
        }
        return list;
    }

    private class Reward implements Weight {

        int type;
        int id;
        int weight;

        public Reward(int type, int id, int weight) {
            this.type = type;
            this.id = id;
            this.weight = weight;
        }

        @Override
        public int getWeight() {
            return weight;
        }
    }

    //数据归档到数据库
    public static void saveToDB(String playerCode) {
        try {
            long updateTime = System.currentTimeMillis();
            //存储
            List<SoulPo> soulPoList = new ArrayList<>();
            RMap<String, Soul> rMap = touch(playerCode);
            if (rMap.isExists()) {
                Map<String, Soul> souls = rMap.readAllMap();
                for (String key : souls.keySet()) {
                    Soul value = souls.get(key);
                    SoulPo soulPo = new SoulPo();
                    soulPo.setPlayerCode(playerCode);
                    soulPo.setCode(value.getCode());
                    soulPo.setDataId(value.getDataId());
                    soulPo.setHero(value.getHero());
                    soulPo.setPropertyIds(arrayList2String(value.getPropertyIds()));
                    soulPo.setQuality(value.getQuality());
                    soulPo.setRefine(value.getRefine());
                    soulPo.setSkillIds(arrayList2String(value.getSkillIds()));
                    soulPo.setRePropertyIds(arrayList2String(value.getRePropertyIds()));
                    soulPo.setReSkillIds(arrayList2String(value.getReSkillIds()));
                    soulPo.setSkillLocks(arrayList2String(value.getSkillLocks()));
                    soulPo.setPropertyLocks(arrayList2String(value.getPropertyLocks()));
                    soulPo.setUpdateTime(updateTime);
                    soulPoList.add(soulPo);
                }
                SoulDAO.replace(soulPoList);

                SoulDAO.delete(playerCode, updateTime);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //从redis移走数据
    public static void removeAllFromRedis(String playerCode) throws RedisException {
        try {
            touchBucket(key(playerCode)).delete();
        } catch (RedisException e) {
            e.printStackTrace();
        }
    }
    // lock==========================================================================

    static private String lockKey(String playerCode) {
        return String.format("lock:%s", key(playerCode));
    }

    static public boolean lockSoul(String playerCode) throws InterruptedException {
        return tryLock(lockKey(playerCode));
    }

    static public void unlockSoul(String playerCode) {
        unlock(lockKey(playerCode));
    }

}
